/* mm5_file.cpp */

#include "mm5_file.h"
#include "sub_header.h"

#ifndef NO_NEED_TO_SWAP_ENDIAN
#include <dodo_utils/swap_endian.h>
#endif // NO_NEED_TO_SWAP_ENDIAN

namespace dodomet
{
namespace mm5
{

MM5_File::MM5_File()
{ };

MM5_File::MM5_File(const std::string& filename)
{
	read_file(filename);
}

MM5_File::MM5_File(const MM5_File& orig)
	: filename_(orig.filename_)
{
	if(!filename_.empty())
		read_file(filename_);
}

MM5_File& MM5_File::operator=(const MM5_File& orig)
{
	filename_ = orig.filename_;
	if(!filename_.empty())
		read_file(filename_);
}

std::string MM5_File::filename() const
{
	return filename_;
}

void MM5_File::read_file(const std::string& filename)
{
	filename_ = filename;
	std::fstream file(filename_.c_str(), 
		std::ios_base::binary | 
		std::ios_base::in);

	if(!file)
	{
		throw exceptions::cannot_open_file(filename);
	}
	
	var_info_list_.clear();
	
	fortran_int dum;
	char* p_dum = reinterpret_cast<char*>(&dum);
	
	fortran_int flag;
	while(file.read(p_dum, sizeof(dum)))
	{
		file.read(reinterpret_cast<char*>(&flag), sizeof(flag));
#ifndef NO_NEED_TO_SWAP_ENDIAN
		dodomet::swap_endian(flag);
#endif // NO_NEED_TO_SWAP_ENDIAN
		file.read(p_dum, sizeof(dum));

		if(flag == 0)
		{
			//Big_Header
			big_header_.read(file);
		}
		else if(flag == 1)
		{
			//Sub_Header
			Sub_Header sh;
			sh.read(file);
			sh.set_start_time(start_time());
			Infolet infolet(*this, sh);
			
			iterator iter = find_var_name(sh.name());
			if(iter == end())
			{
				// the var is not in the list
				Var_Info info(sh);
				info.add_record(infolet);
				var_info_list_.push_back(info);
				ignore_field(info, file);
			}
			else
			{
				// the var is in the list
				iter->add_record(infolet);
				ignore_field(*iter, file);
			}
		}
		else
		{
			// Do nothing.
		}
	}
}

MM5_File::const_iterator MM5_File::begin() const
{
	return var_info_list_.begin();
}

MM5_File::const_iterator MM5_File::end() const
{
	return var_info_list_.end();
}

MM5_File::iterator MM5_File::begin()
{
	return var_info_list_.begin();
}

MM5_File::iterator MM5_File::end()
{
	return var_info_list_.end();
}

int MM5_File::var_num() const
{
	return var_info_list_.size();
}

MM5_File::const_iterator MM5_File::find_var_name(const std::string& var_name) const
{
	for(const_iterator result = begin(); 
		result != end();
		++result)
	{
		if(result->name() == var_name)
			return result;
	}
	return end();
}

MM5_File::iterator MM5_File::find_var_name(const std::string& var_name)
{
	for(iterator result = begin(); 
		result != end();
		++result)
	{
		if(result->name() == var_name)
			return result;
	}
	return end();
}

Big_Header MM5_File::big_header() const
{
	return big_header_;
}

boost::posix_time::ptime MM5_File::start_time() const
{
	return big_header_.start_time();
}

int MM5_File::data_type() const
{
	return big_header_.data_type();
}

void MM5_File::ignore_field(const Var_Info& info, std::fstream& file)
{
	file.seekg(4 * 2 + info.field_size() * sizeof(fortran_real), std::ios_base::cur);
}

} // namespace dodomet::mm5
} // namespace dodomet
